#include "../linux/head.h"
//内核堆栈中入栈内容：
// 任务0堆栈段（即数据段）选择符 $0x17 表示 LDT 表中的索引2项，任务数据段。
// 内核堆栈指针、
// 任务0标志寄存器内容、
// 任务0代码段选择符 0x0f 表示 LDT 表中的索引1项，任务代码段。
// 执行中断返回后需要执行的下一条指令的偏移位置。 $1f 表示将下面标号1的程序段的偏移地址入栈。该偏移位置是 iret 后的一条指令处。

// 当执行 iret 指令时，CPU 把返回地址送入 CS:EIP 中，同时弹出堆栈中标志寄存器内容。
// 由于CPU判断出目的代码段的特权级是3，与当前内核态的0级不同。CPU会把堆栈中的堆栈段选择符和堆栈指针弹出到 SS:ESP 中。
// 由于特权级发上了变化，段寄存器 DS、 ES、 FS 和GS的值变得无效，此时CPU 会把这些段寄存器清零。
// 因此在执行了 iret 指令后需要重新加载这些段寄存器。
// 此后，系统就开始以特权级3运行在任务◎的代码上。所使用的用户态堆栈还是原来在移动之前使用的堆栈。
// 而其内核态堆栈则被指定为其任务数据结构所在页面的顶端开始(PAGE_SIZE+(long) &init task)。
// 由于以后在创建新进程时，需要复制任务0的任务数据结构，包括其用户堆栈指针，因此要求任务0的用户态堆栈在创建任务1（进程1）之前保持“干净”状态。
#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \
	"pushl $0x17\n\t" \
	"pushl %%eax\n\t" \
	"pushfl\n\t" \
	"pushl $0x0f\n\t" \
	"pushl $1f\n\t" \
	"iret\n" \
	"1:\tmovl $0x17,%%eax\n\t" \
	"mov %%ax,%%ds\n\t" \
	"mov %%ax,%%es\n\t" \
	"mov %%ax,%%fs\n\t" \
	"mov %%ax,%%gs" \
	:::"ax")

#define sti() __asm__ ("sti"::)
#define cli() __asm__ ("cli"::)
#define nop() __asm__ ("nop"::)

#define iret() __asm__ ("iret"::)

#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ ("movw %%dx,%%ax\n\t" \
	"movw %0,%%dx\n\t" \
	"movl %%eax,%1\n\t" \
	"movl %%edx,%2" \
	: \
	: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
	"o" (*((char *) (gate_addr))), \
	"o" (*(4+(char *) (gate_addr))), \
	"d" ((char *) (addr)),"a" (0x00080000))

#define set_intr_gate(n,addr) \
	_set_gate(&idt[n],14,0,addr)

// idt 是在head.s设置的变量
// _set_gate 是向idt（中断向量表）中设置中断对应的处理函数
#define set_trap_gate(n,addr) \
	_set_gate(&idt[n],15,0,addr)

#define set_system_gate(n,addr) \
	_set_gate(&idt[n],15,3,addr)

#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
	*(gate_addr) = ((base) & 0xff000000) | \
		(((base) & 0x00ff0000)>>16) | \
		((limit) & 0xf0000) | \
		((dpl)<<13) | \
		(0x00408000) | \
		((type)<<8); \
	*((gate_addr)+1) = (((base) & 0x0000ffff)<<16) | \
		((limit) & 0x0ffff); }

//This macro, _set_tssldt_desc, is used to set a Task State Segment (TSS)
// or Local Descriptor Table (LDT) descriptor in the Global Descriptor Table (GDT) or LDT.
// The TSS is used to store information about a specific task,
// while the LDT is specific to individual tasks or processes.
// "movw $104,%1\n\t": This line moves the value 104 (size of TSS/LDT descriptor) into the memory location pointed by %1 (which will be *(n)).
// "rorl $16,%%eax\n\t": Rotates the 'addr' value in EAX register right by 16 bits, effectively swapping the higher and lower 16 bits.
#define _set_tssldt_desc(n,addr,type) \
__asm__ ("movw $104,%1\n\t" \
	"movw %%ax,%2\n\t" \
	"rorl $16,%%eax\n\t" \
	"movb %%al,%3\n\t" \
	"movb $" type ",%4\n\t" \
	"movb $0x00,%5\n\t" \
	"movb %%ah,%6\n\t" \
	"rorl $16,%%eax" \
	::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \
	 "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \
	)

#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),"0x89")
#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),"0x82")